﻿namespace Probel.NDoctor.Statistics.UnitTests.InMemory
{
    using System.Collections.Generic;
    using System.Linq;

    using Probel.NDoctor.Statistics.Domain;
    using Probel.NDoctor.Statistics.UnitTests.Helpers;

    public class MemoryRepository : IRepository
    {
        #region Fields

        private readonly List<Application> applications;
        private readonly List<SessionDuration> durations;
        private readonly List<StatisticEntry> statistics;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MemoryRepository"/> class.
        /// </summary>
        /// <param name="applications">The users.</param>
        /// <param name="stat">The stat.</param>
        /// <param name="durations">The durations.</param>
        public MemoryRepository(IEnumerable<Application> applications, IEnumerable<StatisticEntry> stat, IEnumerable<SessionDuration> durations)
        {
            this.applications = new List<Application>(applications);
            this.statistics = new List<StatisticEntry>(stat);
            this.durations = new List<SessionDuration>(durations);
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// Gets the users.
        /// </summary>
        public IEnumerable<Application> Applications
        {
            get { return this.applications; }
        }

        /// <summary>
        /// Gets the durations.
        /// </summary>
        public IEnumerable<SessionDuration> Durations
        {
            get { return this.durations; ; }
        }

        /// <summary>
        /// Gets the statistics.
        /// </summary>
        public IEnumerable<StatisticEntry> Statistics
        {
            get { return this.statistics; }
        }

        #endregion Properties

        #region Methods

        public static IRepository Build()
        {
            var apps = Data.Applications;
            var stat = Data.Statistics;
            var dur = Data.Durations;

            return new MemoryRepository(apps, stat, dur);
        }

        /// <summary>
        /// Clears the database. It'll wipe all the data.
        /// </summary>
        public void Clear()
        {
            this.applications.Clear();
            this.durations.Clear();
            this.statistics.Clear();
        }

        /// <summary>
        /// Imports the specified applications into the remote database.
        /// </summary>
        /// <param name="applications">The applications.</param>
        /// <param name="statistics">The statistics.</param>
        /// <param name="durations">The durations.</param>
        public void Import(IEnumerable<Application> applications, IEnumerable<StatisticEntry> statistics, IEnumerable<SessionDuration> durations)
        {
            this.applications.AddRange(applications);
            this.statistics.AddRange(statistics);
            this.durations.AddRange(durations);
        }

        /// <summary>
        /// Exports the specified statistics into the remote repository.
        /// </summary>
        /// <param name="statistics">The statistics.</param>
        public void Insert(IEnumerable<StatisticEntry> statistics)
        {
            this.statistics.AddRange(statistics);
        }

        /// <summary>
        /// Insert a new user into the database
        /// </summary>
        /// <param name="user">The user.</param>
        public void Insert(Application user)
        {
            this.applications.Add(user);
        }

        /// <summary>
        /// Exports the specified durations into the remote repository.
        /// </summary>
        /// <param name="durations">The durations.</param>
        public void Insert(IEnumerable<SessionDuration> durations)
        {
            this.durations.AddRange(durations);
        }

        /// <summary>
        /// Exports the specified durations into the remote repository.
        /// </summary>
        /// <param name="duration"></param>
        public void Insert(SessionDuration duration)
        {
            this.durations.Add(duration);
        }

        /// <summary>
        /// Inserts the specified statistic into the remote repository.
        /// </summary>
        /// <param name="statistic">The statistic.</param>
        public void Insert(StatisticEntry statistic)
        {
            this.statistics.Add(statistic);
        }

        /// <summary>
        /// Updates the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        public void Update(Application application)
        {
            var toUpdate = (from a in this.Applications
                            where a.ApplicationKey == application.ApplicationKey
                            select a).Single();

            application.InstallationDate = toUpdate.InstallationDate;
            application.LastUpdate = toUpdate.LastUpdate;
            application.UpdateVersion = toUpdate.UpdateVersion;
            application.Version = toUpdate.Version;
        }

        #endregion Methods
    }
}